package com.cordys.opensource.crom.sql;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.cordys.cpc.bsf.busobject.BusObject;
import com.cordys.cpc.bsf.classinfo.RelationInfo_FK;
import com.cordys.opensource.crom.BusObjectHelper;
import com.cordys.opensource.crom.sql.Where.Operator;

public class Join {

	private final JoinType sType;
	private final Table oPrimaryTable;
	private final Table oSecondaryTable;
	private final List<Where> onParts = new ArrayList<Where>();
	
	public enum JoinType
	{
		Inner		(" inner join "),
		LeftOuter	(" left outer join "),
		RightOuter	(" right outer join "),
		Full		(" full join ");
		private final String type;
		JoinType(String type)
		{
			this.type = type;
		}
		public String toString()
		{
			return type;
		}
	}
	
	/**
	 * Joins the two tables on their foreign key relationship
	 * @param type
	 * @param primaryTable
	 * @param secondaryTable
	 */
	Join(JoinType type, Table primaryTable, Table secondaryTable)
	{
		sType = type;
		oPrimaryTable = primaryTable;
		oSecondaryTable = secondaryTable;
	}
	
	/**
	 * Joins the two tables on their foreign key relationship
	 * @param type
	 * @param primaryTable
	 * @param secondaryTable
	 */
	Join(JoinType type, Table primaryTable, Table secondaryTable, RelationInfo_FK foreignKeyRelation)
	{
		this(type, primaryTable, secondaryTable);
		
		// Now join on the FK attributes
		String[] primaryAttributes = foreignKeyRelation.getLocalAttributes();
		String[] secondaryAttributes = foreignKeyRelation.getRelatedAttributes();
		// Check the direction of the foreign key; if required swap
		Class<? extends BusObject> relatedClass = BusObjectHelper.getRelatedClass(foreignKeyRelation);
		if (primaryTable.getPersistenceClass().equals(relatedClass))
		{
			primaryAttributes = foreignKeyRelation.getRelatedAttributes();
			secondaryAttributes = foreignKeyRelation.getLocalAttributes();
		}
		
		for (int i=0; i<primaryAttributes.length; i++)
		{
			Column primaryColumn = oPrimaryTable.getColumn(primaryAttributes[i]);
			Column secondaryColumn = oSecondaryTable.getColumn(secondaryAttributes[i]);
			onParts.add(new Where(primaryColumn.getQuery(), "", primaryColumn, "", Operator.Equals, "", secondaryColumn, ""));
		}
	}
	
	public Table getSecondaryTable()
	{
		return oSecondaryTable;
	}
	
	public JoinType getType()
	{
		return sType;
	}
	
	public String toString()
	{
		StringBuilder string = new StringBuilder(sType.toString() + oSecondaryTable.toString() + " on (");
		
		Iterator<Where> i = onParts.iterator();
		while (i.hasNext())
		{
			string.append(i.next());
			if (i.hasNext())
			{
				string.append(" and ");
			}
		}
		return string.append(")").toString();
	}
	
	/**
	 * Adds a ON statement to the join.
	 * @param where
	 * @return
	 */
	public Where on(Column column, Operator operator, Object operand)
	{
		Where where = new Where(column.getQuery(), "", column, "", operator, "", operand, "");
		onParts.add(where);
		return where;
	}
}
